package com.milo.utils;

import org.apache.commons.codec.binary.Hex;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.KeyFactory;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/***
* @description: 支付工具类
* @author: Milogenius
* @date: 2018/6/26 18:10
**/
public class PayUtils {

    /**
     * 日志
     */
    private static Logger logger = LoggerFactory.getLogger(PayUtils.class);

    public static String encodeByte2HexString(byte[] bytes) {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        try {
            return new String(Hex.encodeHex(bytes));
        } catch (Exception e) {
            logger.error("error:{}", e.getMessage());
            return null;
        }
    }

    public static byte[] decodeHexString2Byte(String hexStr) {
        if (hexStr == null || hexStr.length() <= 0) {
            return null;
        }
        try {
            return Hex.decodeHex(hexStr.toCharArray());
        } catch (Exception e) {
            logger.error("error:{}", e.getMessage());
            return null;
        }
    }

    public static String signSHA1WithRSA(String data, String strHexPrivateKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decodeHexString2Byte(strHexPrivateKey)));
            Signature sig = Signature.getInstance("SHA1WithRSA");
            sig.initSign(rsaPrivateKey);
            sig.update(data.getBytes("GBK"));
            return encodeByte2HexString(sig.sign());
        } catch (Exception e) {
            logger.error("error:{}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 验签
     * @param data  数据
     * @param strHexPublicKey  密钥
     * @param sign 验证码
     * @return
     */
    public static boolean signVerifySHA1WithRSA(String data, String strHexPublicKey, String sign) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(decodeHexString2Byte(strHexPublicKey)));
            logger.info("需要验签的数据：" + data);
            Signature sig = Signature.getInstance("SHA1WithRSA");
            sig.initVerify(rsaPublicKey);
            sig.update(data.getBytes("GBK"));
            if (sig.verify(decodeHexString2Byte(sign))) {
                logger.info("RSA验签正确");
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.error("error:{}", e.getMessage());
            return false;
        }
    }

    /**
     * 验签
     * @param map
     * @param xml
     * @param key
     * @param doc
     * @return
     */
	public static boolean validationXml(Map<String, String> map, String xml,String key, Document doc) {
		logger.info("需要验签的xml报文"+xml);
		boolean ret = false;
		String busiData = "";//业务数据
		String transactionId = "";//全网唯一流水号
		String xmlSign = "";//验证码
		try {
			List<String> noIsNode = new ArrayList<String>();// 不参与加密的字段
			noIsNode.add("VerifyCode");//验证码
			noIsNode.add("DigestAlg");//签名算法
			Document document = DocumentHelper.parseText(xml);
			// String verifyCode = createSign(document, noIsNode);
			String digestAlg = doc.getRootElement().element("PubInfo").elementText("DigestAlg").trim();
			busiData = document.getRootElement().element("BusiData").asXML();
			Element root = doc.getRootElement();
			List<Element> rootList = root.elements();
			for (Element element : rootList) {
				List<Element> rootList2 = element.elements();
				for (Element element2 : rootList2) {
					if (element2.getName().equals("TransactionId")) {
						transactionId = element2.getText().trim();
					} else if (element2.getName().equals("VerifyCode")) {
						xmlSign = element2.getText().trim();
					}
					map.put(element2.getName(), element2.getText().trim());
				}
			}
			String verifyCode = MD5Utils.sign(transactionId + busiData, key, "UTF-8");
			if (!digestAlg.equals("") && !transactionId.equals("") && !busiData.equals("") && !xmlSign.equals("")) {
				logger.info("verifyCode" + verifyCode);
				logger.info("xmlSign" + xmlSign);
				if (verifyCode.equals(xmlSign)) {
					ret = true;
				} else {
					logger.info("杭研支付报文验签失败");
				}
			} else {
				logger.info("杭研支付报文获取加密方式为空");
			}
		} catch (Exception e) {
			logger.error("杭研支付报文验签报错:" + e);
			e.printStackTrace();
		}
		return ret;
	}

    /**
     *
     * 功能描述：金额字符串转换：单位分转成单元

     * @param o 传入需要转换的金额字符串
     * @return 转换后的金额字符串
     */
    public static String fenToYuan(Object o) {
        if(o == null)
            return "0.00";
        String s = o.toString();
        int len = -1;
        StringBuilder sb = new StringBuilder();
        if (s != null && s.trim().length()>0 && !s.equalsIgnoreCase("null")){
            s = removeZero(s);
            if (s != null && s.trim().length()>0 && !s.equalsIgnoreCase("null")){
                len = s.length();
                int tmp = s.indexOf("-");
                if(tmp>=0){
                    if(len==2){
                        sb.append("-0.0").append(s.substring(1));
                    }else if(len==3){
                        sb.append("-0.").append(s.substring(1));
                    }else{
                        sb.append(s.substring(0, len-2)).append(".").append(s.substring(len-2));
                    }
                }else{
                    if(len==1){
                        sb.append("0.0").append(s);
                    }else if(len==2){
                        sb.append("0.").append(s);
                    }else{
                        sb.append(s.substring(0, len-2)).append(".").append(s.substring(len-2));
                    }
                }
            }else{
                sb.append("0.00");
            }
        }else{
            sb.append("0.00");
        }
        return sb.toString();
    }

    /**
     *
     * 功能描述：金额字符串转换：单位元转成单分

     * @param o 传入需要转换的金额字符串
     * @return 转换后的金额字符串
     */
    public static String yuanToFen(Object o) {
        if (o == null) {
            return "0";
        }
        String s = o.toString();
        int posIndex = -1;
        String str = "";
        StringBuilder sb = new StringBuilder();
        if (s != null && s.trim().length()>0 && !s.equalsIgnoreCase("null")){
            posIndex = s.indexOf(".");
            if(posIndex>0){
                int len = s.length();
                if(len == posIndex+1){
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append("00");
                }else if(len == posIndex+2){
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append(s.substring(posIndex+1,posIndex+2)).append("0");
                }else if(len == posIndex+3){
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append(s.substring(posIndex+1,posIndex+3));
                }else{
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append(s.substring(posIndex+1,posIndex+3));
                }
            }else{
                sb.append(s).append("00");
            }
        }else{
            sb.append("0");
        }
        str = removeZero(sb.toString());
        if(str != null && str.trim().length()>0 && !str.trim().equalsIgnoreCase("null")){
            return str;
        }else{
            return "0";
        }
    }
    public static String removeZero(String str){
        char  ch;
        String result = "";
        if(str != null && str.trim().length()>0 && !str.trim().equalsIgnoreCase("null")){
            try{
                for(int i=0;i<str.length();i++){
                    ch = str.charAt(i);
                    if(ch != '0'){
                        result = str.substring(i);
                        break;
                    }
                }
            }catch(Exception e){
                result = "";
            }
        }else{
            result = "";
        }
        return result;

    }
}
